package cn.bisoft.java.service.ext.httpclient.common.impl;

import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.XMLContext;
import org.xml.sax.InputSource;

import cn.bisoft.java.bean.message.TransMessage;
import cn.bisoft.java.bean.vo.SignatureType;
import cn.bisoft.java.constants.Constants;
import cn.bisoft.java.service.ext.httpclient.common.MappingFileConfig;
import cn.bisoft.java.service.ext.httpclient.common.MessageConverter;
import cn.bisoft.java.service.ext.httpclient.common.MessageHelper;
import cn.bisoft.java.util.config.ConfigProvider;
import cn.bisoft.java.util.config.ConfigProviderFactory;

import com.hengpeng.common.msg.agentportal.MessengerDao;

public class MessageConverterImpl implements MessageConverter
{
	private final static class LazyInstance
	{
		public final static MessageConverterImpl foo = new MessageConverterImpl();
	}

	private final static Log logger = LogFactory.getLog(MessageConverterImpl.class);

	private final static Map<String, Map<Integer, XMLContext>> versionMap = new HashMap<String, Map<Integer, XMLContext>>();

	public final static MessageConverterImpl getInstance()
	{
		return LazyInstance.foo;
	}

	public String encoding = Constants.MESSAGE_AGENTPORTAL_ENCODING;

	private MessengerDao messengerdao;

	private MessageConverterImpl()
	{
		loadConfig();
	}

	public TransMessage deserialize(String xml, int transType)
	{
		if (null != this.messengerdao)
		{
			return deserialize(xml, transType, null, null);
		}
		return null;
	}

	public TransMessage deserialize(String xml, int transType, String password, String signType)
	{
		try
		{
			Unmarshaller unmarshaller = null;
			StringReader reader = null;
			String version = MessageHelper.getVersion(xml);
			Map<Integer, XMLContext> xmlcontexts = versionMap.get(version);
			if (xmlcontexts != null)
			{
				XMLContext context = xmlcontexts.get(transType);
				if (context != null)
				{
					unmarshaller = context.createUnmarshaller();
					reader = new StringReader(xml);
					TransMessage message = (TransMessage) unmarshaller.unmarshal(reader);

					MessageHelper.verifyTimestamp(message);

					MessageHelper.verifyMessageId(message);

					MessageHelper.verifyTransType(message, transType);

					if (password == null)
					{
						String msgerPwd = this.messengerdao.getMessengerPwd(message.getHeader().getMessengerID());
						if ((signType != null) && (signType.length() > 0)
								&& (SignatureType.valueOf(signType).equals(SignatureType.RSA)))
						{
							MessageHelper.verifyRSADigest(message, xml, msgerPwd, this.getEncoding());
						}
						else
						{
							MessageHelper.verifyDigest(message, xml, msgerPwd, this.getEncoding());
						}
					}
					else
					{
						if ((signType != null) && (signType.length() > 0)
								&& (SignatureType.valueOf(signType).equals(SignatureType.RSA)))
						{
							MessageHelper.verifyRSADigest(message, xml, password, this.getEncoding());
						}
						else
						{
							MessageHelper.verifyDigest(message, xml, password, this.getEncoding());

						}
					}

					return message;
				}
				else
				{
				}
			}
		}
		catch (Exception e)
		{
		}
		return null;
	}

	public TransMessage deserializeNoValid(String xml, int transType)
	{

		Unmarshaller unmarshaller = null;
		StringReader reader = null;
		try
		{
			String version = MessageHelper.getVersion(xml);
			Map<Integer, XMLContext> xmlcontexts = versionMap.get(version);
			if (xmlcontexts != null)
			{
				XMLContext context = xmlcontexts.get(transType);
				if (context != null)
				{
					unmarshaller = context.createUnmarshaller();
					reader = new StringReader(xml);
					TransMessage message = (TransMessage) unmarshaller.unmarshal(reader);
					return message;
				}
				else
				{
				}
			}
			else
			{
			}
		}
		catch (Exception e)
		{
		}
		return null;
	}

	public String getEncoding()
	{
		return this.encoding;
	}

	public MessengerDao getMessengerdao()
	{
		return this.messengerdao;
	}

	private void loadConfig()
	{
		try
		{
			ConfigProvider vercp = ConfigProviderFactory.getInstance(Constants.CASTOR_MAPFILEPATH_CONFIG,
					MappingFileConfig.class);
			Map<String, MappingFileConfig> versionConfigMap = vercp.getAllConfig();
			MappingFileConfig baseVersion = versionConfigMap.get(Constants.PROTOCOL_VERSION);
			Map<Integer, XMLContext> baseContexts = new HashMap<Integer, XMLContext>();
			MappingFileConfig header = null;
			if (baseVersion != null)
			{
				String versionFile = baseVersion.getImportFile();
				ConfigProvider cp = ConfigProviderFactory.getInstance(versionFile, MappingFileConfig.class);
				Map<String, MappingFileConfig> transConfigMap = cp.getAllConfig();
				for (Iterator<Entry<String, MappingFileConfig>> iter = transConfigMap.entrySet().iterator(); iter
						.hasNext();)
				{
					Entry<String, MappingFileConfig> transElement = iter.next();
					if (transElement.getKey().toString().equals(Constants.TRANSTYPE_COMMON_HEADER))
					{
						continue;
					}

					ClassLoader cld = Thread.currentThread().getContextClassLoader();

					header = (MappingFileConfig) transConfigMap.get(Constants.TRANSTYPE_COMMON_HEADER);
					InputStream his = cld.getResourceAsStream(header.getFilePath());
					Mapping mapping = new Mapping();
					mapping.loadMapping(new InputSource(his));

					MappingFileConfig mfc = (MappingFileConfig) transElement.getValue();
					InputStream is = cld.getResourceAsStream(mfc.getFilePath());
					mapping.loadMapping(new InputSource(is));
					XMLContext xmlcontext = new XMLContext();
					xmlcontext.addMapping(mapping);
					baseContexts.put(Integer.parseInt(transElement.getKey()), xmlcontext);
				}
				versionMap.put(Constants.PROTOCOL_VERSION, baseContexts);
			}

			for (Iterator<Entry<String, MappingFileConfig>> versioniter = versionConfigMap.entrySet().iterator(); versioniter
					.hasNext();)
			{
				Entry<String, MappingFileConfig> versionElement = versioniter.next();
				MappingFileConfig versionConfig = versionElement.getValue();
				String version = versionElement.getKey();
				if (Constants.PROTOCOL_VERSION.equalsIgnoreCase(version))
				{
					continue;
				}
				else
				{
					String versionFile = versionConfig.getImportFile();
					ConfigProvider cp = ConfigProviderFactory.getInstance(versionFile, MappingFileConfig.class);
					Map<String, MappingFileConfig> transConfigMap = cp.getAllConfig();
					Map<Integer, XMLContext> transContexts = new HashMap<Integer, XMLContext>();
					transContexts.putAll(baseContexts);
					for (Iterator<Entry<String, MappingFileConfig>> iter = transConfigMap.entrySet().iterator(); iter
							.hasNext();)
					{
						Entry<String, MappingFileConfig> transElement = iter.next();
						if (transElement.getKey().toString().equals(Constants.TRANSTYPE_COMMON_HEADER))
						{
							continue;
						}

						ClassLoader cld = Thread.currentThread().getContextClassLoader();

						if (header == null)
						{
							header = (MappingFileConfig) transConfigMap.get(Constants.TRANSTYPE_COMMON_HEADER);
						}
						InputStream his = cld.getResourceAsStream(header.getFilePath());
						Mapping mapping = new Mapping();
						mapping.loadMapping(new InputSource(his));

						MappingFileConfig mfc = (MappingFileConfig) transElement.getValue();
						InputStream is = cld.getResourceAsStream(mfc.getFilePath());
						mapping.loadMapping(new InputSource(is));
						XMLContext xmlcontext = new XMLContext();
						xmlcontext.addMapping(mapping);
						transContexts.put(Integer.parseInt(transElement.getKey()), xmlcontext);
					}
					versionMap.put(version, transContexts);
				}
			}
		}
		catch (Exception e)
		{
		}
	}

	public String serialize(TransMessage message, int transType)
	{
		if (null != this.messengerdao)
		{
			return serialize(message, transType, null, null);
		}
		return null;
	}

	public String serialize(TransMessage message, int transType, String password, String signType)
	{
		Marshaller marshaller = null;
		StringWriter writer = null;
		try
		{
			String version = message.getVersion();
			Map<Integer, XMLContext> xmlcontexts = versionMap.get(version);
			if (xmlcontexts != null)
			{
				XMLContext context = xmlcontexts.get(transType);
				if (context != null)
				{
					marshaller = context.createMarshaller();
					writer = new StringWriter();
					marshaller.setWriter(writer);
					marshaller.setEncoding(this.encoding);

					message.getHeader().setDigest("");
					marshaller.marshal(message);

					String transMessage = writer.toString();

					if (password == null)
					{
						String msgerPwd = this.messengerdao.getMessengerPwd(message.getHeader().getMessengerID());

						if ((signType != null) && (signType.length() > 0)
								&& (SignatureType.valueOf(signType).equals(SignatureType.RSA)))
						{
							transMessage = MessageHelper.digestRSAMessage(message, transMessage, msgerPwd, this
									.getEncoding());
						}
						else
						{
							transMessage = MessageHelper.digestMessage(message, transMessage, msgerPwd, this
									.getEncoding());
						}
					}
					else
					{
						if ((signType != null) && (signType.length() > 0)
								&& (SignatureType.valueOf(signType).equals(SignatureType.RSA)))
						{
							transMessage = MessageHelper.digestRSAMessage(message, transMessage, password, this
									.getEncoding());
						}
						else
						{
							transMessage = MessageHelper.digestMessage(message, transMessage, password, this
									.getEncoding());
						}
					}

					return transMessage;
				}
				else
				{
				}
			}
			else
			{
			}
		}
		catch (Exception e)
		{
		}
		return null;
	}

	public String serializeNoValid(TransMessage message, int transType)
	{

		Marshaller marshaller = null;
		StringWriter writer = null;
		try
		{
			String version = message.getVersion();
			Map<Integer, XMLContext> xmlcontexts = versionMap.get(version);
			if (xmlcontexts != null)
			{
				XMLContext context = xmlcontexts.get(transType);
				if (context != null)
				{
					marshaller = context.createMarshaller();
					writer = new StringWriter();
					marshaller.setWriter(writer);
					marshaller.setEncoding(this.encoding);

					message.getHeader().setDigest("");
					marshaller.marshal(message);

					String transMessage = writer.toString();

					String msgerPwd = null;
					try
					{
						msgerPwd = this.messengerdao.getMessengerPwd(message.getHeader().getMessengerID());
					}
					catch (RuntimeException e)
					{
						logger.info("�����̲�����" + message.getHeader().getMessengerID()
								+ ", ��ʹ�ÿյĴ������������Ϣ�����ժҪ.");
						msgerPwd = "";
					}
					transMessage = MessageHelper.digestMessage(message, transMessage, msgerPwd, this.getEncoding());

					return transMessage;
				}
				else
				{
				}
			}
			else
			{
			}
		}
		catch (Exception e)
		{
		}
		return null;
	}

	public void setEncoding(String encoding)
	{
		this.encoding = encoding;
	}

	public void setMessengerdao(MessengerDao messengerdao)
	{
		this.messengerdao = messengerdao;
	}

	public boolean validDigest(String xml)
	{
		String msnerId = MessageHelper.getMessengerId(xml);
		String msgerPwd = this.messengerdao.getMessengerPwd(msnerId);
		return MessageHelper.verifyDigest(xml, msgerPwd, this.getEncoding());
	}

	public boolean validDigest(String xml, String agentPwd)
	{
		return MessageHelper.verifyDigest(xml, agentPwd, this.getEncoding());
	}
}
